// 定义字符串变量
let str: string = "hello";
let str2: string;
str2 = "world";

// 自动类型推断
let str3 = "hi";
// str3 = 10;

// 定义数字类型
let num: number = 1;
num += 10;

// 定义布尔类型
let done: boolean = true;
done = false;

// 定义undefined
let udf: undefined = undefined;

// 定义null
let nl: null = null;

// 联合类型
let a: number | boolean | string = 3;
a = true;
a = "3";
// const token: string | null = localStorage.getItem("token");
// if (token) {
//   token.split("");
// }

// 任意类型 any
let arr1: any = [1, 2, 3, 4];
arr1 = "3";

// 数组的定义
let arr2: number[] = [1, 2, 3, 4, 5];
let arr3: Array<string> = ["1", "2", "3"]; // 泛型的写法
let arr4: (number | boolean)[] = [1, 3, true];
let arr5: Array<number | boolean> = [1, 3, true];
let arr6: (number | boolean | string[])[] = [1, true, ["2", "4", "6"]];
let arr7: any[] = [1, true, ["2", "4", "6"]];
let arr8: any = [1, true, ["2", "4", "6"]];

// 元组的定义Tuple
// 特殊的数组，规定了数组的长度，并且规定了里面的每一项的数据类型
let arr11: [number, string] = [123, "abc"];
// arr11[2] 不能进行越界访问
// console.log(arr11[2]);

// 对象类型
// interface接口, 可以使用interface来自己定义类型
// 首字母大写，用分号结束
interface ObjType {
  name: string;
  age: number;
  // 问号表示可选参数
  sex?: number | string;
  // 索引签名
  // 这个对象可以任意扩展了
  [propname: string]: any;
}
let obj1: ObjType = {
  name: "zhangsan",
  age: 20,
};
let obj2: ObjType = {
  name: "lisi",
  age: 30,
  sex: 1,
  a: 3,
  b: 4,
  c: true,
};

interface Obj3Type {
  id: number;
  name: string;
  likes: number[];
}
let obj3: Obj3Type = {
  id: 1,
  name: "zhangsan",
  likes: [299, 399, 699],
};

interface ItemType {
  id: number;
  name: string;
  likes?: number[];
}
let list: ItemType[] = [
  {
    id: 1,
    name: "zhangsan",
    likes: [299, 399, 699],
  },
  {
    id: 2,
    name: "lisi",
  },
];

interface Obj4Type {
  name: string;
  age: number;
  children?: Obj4Type[];
}
let obj4: Obj4Type = {
  name: "laozhang",
  age: 50,
  children: [
    {
      name: "xiaozhang",
      age: 25,
    },
    {
      name: "xxzhang",
      age: 20,
    },
  ],
};

// 枚举类型 Enum
// 非常类似于对象，不仅可以通过key去找value，也可以通过value去找key
enum Color {
  Red = 10,
  Green = 20,
  Blue = 30,
}
let g: Color = Color.Green;
// console.log(g); // 1
let colorname: string = Color[30];
// console.log(colorname); // Blue

// 函数类型
// 指的是函数的返回值类型
function add(): number {
  return 5;
}
// 函数的参数是没有自动类型推断的
// 函数参数也可以加？表示可选参数
// 可选参数一定要放在必选参数的后面
function add2(x: number, y?: string): string {
  return y ? x + y : x + "";
}
add2(3, "4");
add2(3);

// void表示没有类型，只能给函数用，表示函数没有返回值
function add3(x: number, y: number): void {
  console.log(x + y);
}
// add3(3, 4);

// never表示从不，只能给函数用，死循环和报错的时候用
function add4(): never {
  while (true) {}
}
function add5(): never {
  throw new Error();
}

// (x: string, y: string) => string表示函数类型，写法很像箭头函数
const add6: (x: string, y: string) => string = (
  x: string,
  y: string
): string => {
  return x + y;
};
add6("a", "b");

// 泛型类型
// 相当于是函数参数类型的形参
function add7<T>(x: T, y: T) {
  return `${x}${y}`;
}
add7<number>(3, 4);

// vue3定义响应式数据
// const count = ref<number>(5);

// 类的定义
interface Type {
  name: string;
}
class Animal {
  constructor(obj: Type) {
    // console.log("Animal");
    this.name = obj.name;
  }
  // static age: number = 20;
  name: string = "dog";
  sayName(): string {
    return this.name;
  }
}
// 类的继承,会继承里面的属性和方法,除了static以外
class Cat extends Animal {
  // 类里面有一个constructor函数，当这个类被实例化的时候就会自动触发
  constructor(obj: Type) {
    // console.log("Cat");
    // 不是最大的类的constructor，需要里面调用super函数
    // 调用super函数，相当于调用了父类的constructor
    super(obj);
  }
}
// 类的实例化
const cat = new Cat({
  name: "cat",
});
console.log(cat.name); // cat
